package com.znjc.device.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.znjc.common.constant.DeviceConstants;
import com.znjc.common.core.domain.entity.SysDictData;
import com.znjc.common.utils.DictUtils;
import com.znjc.common.utils.StringUtils;
import com.znjc.device.domain.*;
import com.znjc.device.domain.vo.DeviceTypeVO;
import com.znjc.device.domain.vo.DeviceVO;
import com.znjc.device.domain.vo.HomePageDataVO;
import com.znjc.device.domain.vo.IotData;
import com.znjc.device.mapper.CxDataMapper;
import com.znjc.device.mapper.DeviceDeviceMapper;
import com.znjc.device.mapper.HlDataMapper;
import com.znjc.device.service.*;
import com.znjc.device.util.DateUtil;
import com.znjc.system.service.ISysDictDataService;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static com.znjc.common.utils.SecurityUtils.getDeptId;
import static com.znjc.common.utils.Threads.sleep;

/**
 * 【请填写功能名称】Service业务层处理
 *
 * @author zengpc
 * @date 2023-12-04
 */
@Service
public class DeviceDeviceServiceImpl extends ServiceImpl<DeviceDeviceMapper, DeviceDevice> implements IDeviceDeviceService {
    @Autowired
    private IDevicePointService devicePointService;
    @Autowired
    private IDeviceTypeService deviceTypeService;
    @Autowired
    private IDeviceAlarmService deviceAlarmService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    DeviceDataService deviceDataService;
    @Resource
    ISysDictDataService sysDictDataService;
    @Autowired
    private IIotSerialService iotSerialService;
    @Resource
    CxDataMapper cxDataMapper;
    @Resource
    HlDataMapper hlDataMapper;

    @Override
    public void editDeviceStatus(Long deviceId, Boolean status) {
        DeviceDevice device = this.getById(deviceId);
        if (null != device) {
            device.setDeviceStatus(status ? "0" : "1");
            device.setUpdateBy("admin");
            device.setUpdateTime(new Date());
            this.updateById(device);
        }
    }

    @Override
    public List<DeviceDevice> getListByDeptId(Long deptId) {
        LambdaQueryWrapper<DeviceDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DeviceDevice::getDeptId, deptId);
        wrapper.eq(DeviceDevice::getStatus, "0");
        wrapper.eq(DeviceDevice::getStatus, "0");
        wrapper.isNull(DeviceDevice::getHuiliu);
        return this.list(wrapper);
    }

    @Override
    public List<Long> getIdsByDxbh(String dxbh) {
        LambdaQueryWrapper<DeviceDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DeviceDevice::getStatus, "0");
        wrapper.eq(DeviceDevice::getDelFlag, "0");
        wrapper.eq(DeviceDevice::getDxbh, dxbh);
        List<DeviceDevice> list = this.list(wrapper);
        if (CollectionUtils.isNotEmpty(list)) {
            return list.stream().map(DeviceDevice::getId).collect(Collectors.toList());
        }
        return new ArrayList<>();
    }

    @Override
    public JSONObject updateDeviceDataWs() {
        JSONObject data = new JSONObject();
        data.put("sydata", true);
        //设备实时数据
        data.put("datas", getData());
        //设备状态
        data.put("ztPie", getSbztSeriesData());
        //近一月告警统计
        data.put("lbLine", getDeviceAlarmLine());

        return data;
    }

    /**
     * 实时数据
     *
     * @return
     */
    public HomePageDataVO getData() {
        List<DeviceTypeVO> typeVOS = new ArrayList<>();
        //设备数据
        LambdaQueryWrapper<DeviceType> typeQuery = new LambdaQueryWrapper<>();
        typeQuery.eq(DeviceType::getDelFlag, "0");
        typeQuery.eq(DeviceType::getStatus, "0");
        List<DeviceType> types = deviceTypeService.list(typeQuery);
        if (CollectionUtils.isNotEmpty(types)) {
            types.stream().forEach(type -> {
                DeviceTypeVO typeVO = new DeviceTypeVO();
                typeVO.setName(type.getName());
                typeVO.setId(type.getId());
                LambdaQueryWrapper<DeviceDevice> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(DeviceDevice::getDelFlag, "0");
                wrapper.eq(DeviceDevice::getStatus, "0");
                wrapper.orderByAsc(DeviceDevice::getCreateTime);
                List<DeviceDevice> list = this.list(wrapper);
                List<DeviceVO> vos = new ArrayList<>();
                if (CollectionUtils.isNotEmpty(list)) {
                    list.forEach(device -> {
                        String tableName = DeviceConstants.TABLE_NAME + device.getId() + "_";
                        String addressBitmap = redisTemplate.opsForValue().get(DeviceConstants.GGD);
                        String address = "";
                        if ("0".equals(device.getIsDt()) && StringUtils.isNotEmpty(device.getMasterCode())) {
                            address = device.getMasterCode() + "_" + addressBitmap;
                        } else if (StringUtils.isNotEmpty(device.getAddressBitmap())) {
                            address = device.getAddressBitmap().replaceAll(",", "_");
                        }
                        tableName += address;
                        IotData dataVo = JSONObject.parseObject(redisTemplate.opsForValue().get(tableName), IotData.class);
                        if (null != dataVo) {
                            try {
                                if ("0".equals(device.getXsdx())) {
                                    vos.add(getDeviceVO(device, dataVo, 0, address));
                                } else if ("1".equals(device.getXsdx())) {
                                    vos.add(getDeviceVO(device, dataVo, 1, address));
                                } else if ("2".equals(device.getXsdx())) {
                                    vos.add(getDeviceVO(device, dataVo, 2, address));
                                }
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            }
                        }
                    });
                }
                typeVO.setDeviceVOS(vos);
                typeVOS.add(typeVO);
            });
        }
        //磁芯
        CxData cxData = JSONObject.parseObject(redisTemplate.opsForValue().get(DeviceConstants.CX), CxData.class);
        //回流
        HlData hlData = JSONObject.parseObject(redisTemplate.opsForValue().get(DeviceConstants.HL), HlData.class);
        HomePageDataVO dataVO = new HomePageDataVO();
        dataVO.setTypeVOS(typeVOS);
        dataVO.setHlData(hlData);
        dataVO.setCxData(cxData);
        return dataVO;
    }


    /**
     * @param device
     * @param dataVo
     * @param type   0电阻 1电压
     * @return
     */
    private DeviceVO getDeviceVO(DeviceDevice device, IotData dataVo, int type, String address) throws Exception {
        DeviceVO vo = new DeviceVO();
        vo.setDeviceId(device.getId());
        vo.setDeviceName(device.getDeviceName());
        if (type == 0) {
            vo.setValue(dataVo.getDz());
            vo.setUnit(dataVo.getDzUnit());
        } else if (type == 1) {
            vo.setValue(dataVo.getDzl());
            vo.setUnit(dataVo.getDzlUnit());
        } else if (type == 2) {
            vo.setValue(dataVo.getDy());
            vo.setUnit(dataVo.getDyUnit());
        }
        vo.setTs(DateUtil.TimestampToString(dataVo.getTs()));
        vo.setStatus(device.getDeviceStatus());
        String[] bitmaps = address.split("_");
        String name = DictUtils.getDictLabel(DeviceConstants.DEVICE_BITMAP, bitmaps[0]) + DictUtils.getDictLabel(DeviceConstants.DEVICE_BITMAP, bitmaps[1]);
        vo.setAddress(name);
        return vo;
    }

    /**
     * 获取当前时间前一月设备告警统计
     *
     * @return
     */
    private JSONObject getDeviceAlarmLine() {
        JSONObject data = new JSONObject();
        List<String> xdata = DateUtil.getBetweenDate(new Date(), -1, 0);
        if (CollectionUtils.isNotEmpty(xdata)) {
            JSONArray seriesData = new JSONArray();
            xdata.forEach(date -> {
                LambdaQueryWrapper<DeviceAlarm> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(DeviceAlarm::getDelFlag, "0");
                wrapper.eq(DeviceAlarm::getStatus, "0");
                wrapper.last(" AND DATE_FORMAT(start_time, '%Y-%m-%d') = '" + date + "'");
                int count = deviceAlarmService.count(wrapper);
                seriesData.add(count);
            });
            data.put("xdata", xdata);
            data.put("seriesData", seriesData);
        }
        return data;
    }

    /**
     * 获取设备状态饼图数据
     *
     * @return
     */
    private JSONArray getSbztSeriesData() {
        LambdaQueryWrapper<DeviceDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DeviceDevice::getDelFlag, "0");
        wrapper.eq(DeviceDevice::getStatus, "0");
        wrapper.eq(DeviceDevice::getDeviceStatus, "0");
        int zcCount = this.count(wrapper);
        wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DeviceDevice::getDelFlag, "0");
        wrapper.eq(DeviceDevice::getStatus, "0");
        wrapper.eq(DeviceDevice::getDeviceStatus, "1");
        int ycCount = this.count(wrapper);
        JSONArray sbztSeriesData = new JSONArray();
        JSONObject series = new JSONObject();
        series.put("value", zcCount);
        series.put("name", "正常");
        sbztSeriesData.add(series);
        series = new JSONObject();
        series.put("value", ycCount);
        series.put("name", "告警");
        sbztSeriesData.add(series);
        return sbztSeriesData;
    }

    @Override
    public JSONObject hisData(Long deviceId) {
        JSONObject data = new JSONObject();
        List<String> xdata = new ArrayList<>();
        List<String> legendData = new ArrayList<>();
        JSONArray seriesData = new JSONArray();
        if (-1 == deviceId.longValue()) {
            //磁芯
            CxData cxData = JSONObject.parseObject(redisTemplate.opsForValue().get(DeviceConstants.CX), CxData.class);
            legendData = packLegendData(DeviceConstants.DEVICE_CX_NAMES, cxData.getMaxDlw());
            LambdaQueryWrapper<CxData> wrapper = new LambdaQueryWrapper<>();
            if (deviceId.longValue() < 0) {
                wrapper.ge(CxData::getTs, DateUtil.getDataByDay(-1));
            } else {
                wrapper.ge(CxData::getTs, DateUtil.getDate(-1));
            }
            List<CxData> datas = cxDataMapper.selectList(wrapper);
            if (CollectionUtils.isNotEmpty(datas)) {
                xdata = datas.stream().map(CxData::getTsString).collect(Collectors.toList());
                List<String> dl;
                for (int i = 0; i < cxData.getMaxDlw(); i++) {
                    if (i == 0) {
                        dl = datas.stream().map(CxData::getDl1).collect(Collectors.toList());
                    } else if (i == 1) {
                        dl = datas.stream().map(CxData::getDl2).collect(Collectors.toList());
                    } else if (i == 2) {
                        dl = datas.stream().map(CxData::getDl3).collect(Collectors.toList());
                    } else if (i == 3) {
                        dl = datas.stream().map(CxData::getDl4).collect(Collectors.toList());
                    } else if (i == 4) {
                        dl = datas.stream().map(CxData::getDl5).collect(Collectors.toList());
                    } else if (i == 5) {
                        dl = datas.stream().map(CxData::getDl6).collect(Collectors.toList());
                    } else if (i == 6) {
                        dl = datas.stream().map(CxData::getDl7).collect(Collectors.toList());
                    } else if (i == 7) {
                        dl = datas.stream().map(CxData::getDl8).collect(Collectors.toList());
                    } else if (i == 8) {
                        dl = datas.stream().map(CxData::getDl9).collect(Collectors.toList());
                    } else if (i == 9) {
                        dl = datas.stream().map(CxData::getDl10).collect(Collectors.toList());
                    } else {
                        dl = new ArrayList<>();
                    }
                    seriesData.add(packSeries(legendData.get(i), dl));
                }
            }
        } else if (-2 == deviceId.longValue()) {
            //回流
            HlData hlData = JSONObject.parseObject(redisTemplate.opsForValue().get(DeviceConstants.HL), HlData.class);
            legendData = packLegendData(DeviceConstants.DEVICE_HL_NAMES, hlData.getMaxDlw());
            LambdaQueryWrapper<HlData> wrapper = new LambdaQueryWrapper<>();
            if (deviceId.longValue() < 0) {
                wrapper.ge(HlData::getTs, DateUtil.getDataByDay(-1));
            } else {
                wrapper.ge(HlData::getTs, DateUtil.getDate(-1));
            }
            List<HlData> datas = hlDataMapper.selectList(wrapper);
            if (CollectionUtils.isNotEmpty(datas)) {
                xdata = datas.stream().map(HlData::getTsString).collect(Collectors.toList());
                List<String> dl;
                for (int i = 0; i < hlData.getMaxDlw(); i++) {
                    if (i == 0) {
                        dl = datas.stream().map(HlData::getDl1).collect(Collectors.toList());
                    } else if (i == 1) {
                        dl = datas.stream().map(HlData::getDl2).collect(Collectors.toList());
                    } else if (i == 2) {
                        dl = datas.stream().map(HlData::getDl3).collect(Collectors.toList());
                    } else if (i == 3) {
                        dl = datas.stream().map(HlData::getDl4).collect(Collectors.toList());
                    } else if (i == 4) {
                        dl = datas.stream().map(HlData::getDl5).collect(Collectors.toList());
                    } else if (i == 5) {
                        dl = datas.stream().map(HlData::getDl6).collect(Collectors.toList());
                    } else if (i == 6) {
                        dl = datas.stream().map(HlData::getDl7).collect(Collectors.toList());
                    } else if (i == 7) {
                        dl = datas.stream().map(HlData::getDl8).collect(Collectors.toList());
                    } else if (i == 8) {
                        dl = datas.stream().map(HlData::getDl9).collect(Collectors.toList());
                    } else if (i == 9) {
                        dl = datas.stream().map(HlData::getDl10).collect(Collectors.toList());
                    } else if (i == 10) {
                        dl = datas.stream().map(HlData::getDl11).collect(Collectors.toList());
                    } else if (i == 11) {
                        dl = datas.stream().map(HlData::getDl12).collect(Collectors.toList());
                    } else if (i == 12) {
                        dl = datas.stream().map(HlData::getDl13).collect(Collectors.toList());
                    } else if (i == 13) {
                        dl = datas.stream().map(HlData::getDl14).collect(Collectors.toList());
                    } else if (i == 14) {
                        dl = datas.stream().map(HlData::getDl15).collect(Collectors.toList());
                    } else if (i == 15) {
                        dl = datas.stream().map(HlData::getDl16).collect(Collectors.toList());
                    } else {
                        dl = new ArrayList<>();
                    }
                    seriesData.add(packSeries(legendData.get(i), dl));
                }
            }
        } else {
            //设备
            DeviceDevice device = this.getById(deviceId);
            if ("0".equals(device.getIsDt())) {
                legendData = DeviceConstants.TABLE_TITLE_DZ;
                String addressBitmap = redisTemplate.opsForValue().get(DeviceConstants.GGD);
                LambdaQueryWrapper<IotData> wrapper = new LambdaQueryWrapper<>();
                wrapper.eq(IotData::getDeviceId, deviceId);
                //主测点与公共点组成一个测试点
                if (StringUtils.isNotEmpty(addressBitmap)) {
                    String address = device.getMasterCode() + "_" + addressBitmap;
                    wrapper.eq(IotData::getAddress, address);
                    wrapper.ge(IotData::getTs, DateUtil.getDataByDay(-1));
                    List<IotData> dataVos = deviceDataService.getListIotData(wrapper);
                    if (CollectionUtils.isNotEmpty(dataVos)) {
                        xdata = dataVos.stream().map(IotData::getTsString).collect(Collectors.toList());
                        List<String> dzs = dataVos.stream().map(IotData::getDz).collect(Collectors.toList());
                        String[] bitmaps = address.split("_");
                        String name = DictUtils.getDictLabel(DeviceConstants.DEVICE_BITMAP, bitmaps[0]) + DictUtils.getDictLabel(DeviceConstants.DEVICE_BITMAP, bitmaps[1]);
                        seriesData.add(packSeries(name + DeviceConstants.POINT_NAME_DZ, dzs));
                    }
                }
                //主测点与每个从测点组成一个测试点
                if (StringUtils.isNotEmpty(device.getSlaveCode())) {
                    String[] slaveCodes = device.getSlaveCode().split(",");
                    String address = null;
                    for (int i = 0; i < slaveCodes.length; i++) {
                        address = device.getMasterCode() + "_" + slaveCodes[i];
                        wrapper.eq(IotData::getAddress, address);
                        wrapper.ge(IotData::getTs, DateUtil.getDate(-1));
                        List<IotData> dataVos = deviceDataService.getListIotData(wrapper);
                        if (CollectionUtils.isNotEmpty(dataVos)) {
                            //xdata = dataVos.stream().map(DataVo::getCreateTime).collect(Collectors.toList());
                            List<String> dzs = dataVos.stream().map(IotData::getDz).collect(Collectors.toList());
                            String[] bitmaps = address.split("_");
                            String name = DictUtils.getDictLabel(DeviceConstants.DEVICE_BITMAP, bitmaps[0]) + DictUtils.getDictLabel(DeviceConstants.DEVICE_BITMAP, bitmaps[1]);
                            seriesData.add(packSeries(name + DeviceConstants.POINT_NAME_DZ, dzs));
                        }
                    }
                }
            } else {
                LambdaQueryWrapper<IotData> wrapper = new LambdaQueryWrapper<>();
                if (deviceId.longValue() < 0) {
                    wrapper.ge(IotData::getTs, DateUtil.getDataByDay(-1));
                } else {
                    wrapper.ge(IotData::getTs, DateUtil.getDate(-1));
                }
                List<IotData> dataVos = deviceDataService.getListIotData(wrapper);
                if (CollectionUtils.isNotEmpty(dataVos)) {
                    xdata = dataVos.stream().map(IotData::getTsString).collect(Collectors.toList());
                    if ("0".equals(device.getXsdx())) {
                        legendData = DeviceConstants.TABLE_TITLE_DZ;
                        List<String> dzs = dataVos.stream().map(IotData::getDz).collect(Collectors.toList());
                        seriesData.add(packSeries(DeviceConstants.POINT_NAME_DZ, dzs));
                    } else if ("1".equals(device.getXsdx())) {
                        legendData = DeviceConstants.TABLE_TITLE_DZL;
                        List<String> dzls = dataVos.stream().map(IotData::getDzl).collect(Collectors.toList());
                        seriesData.add(packSeries(DeviceConstants.POINT_NAME_DZL, dzls));
                    } else if ("2".equals(device.getXsdx())) {
                        legendData = DeviceConstants.TABLE_TITLE_DY;
                        List<String> dys = dataVos.stream().map(IotData::getDy).collect(Collectors.toList());
                        seriesData.add(packSeries(DeviceConstants.POINT_NAME_DY, dys));
                    }
                }
            }

        }
        data.put("legendData", legendData);
        data.put("xdata", xdata);
        data.put("series", seriesData);
        return data;
    }


    private List<String> packLegendData(String name, int num) {
        SysDictData sysDictData = new SysDictData();
        sysDictData.setDictType(name);
        List<String> names = sysDictDataService.selectDictDataList(sysDictData).stream().map(SysDictData::getDictLabel).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(names)) {
            return names.subList(0, num);
        }
        return null;
    }

    private JSONObject packSeries(String name, List<String> data) {
        JSONObject seriesObj = new JSONObject();
        seriesObj.put("name", name);
        seriesObj.put("type", "line");
        seriesObj.put("stack", "Total");
        seriesObj.put("data", data);
        return seriesObj;
    }


    @Override
    public Boolean resetHardWareConfig() {
        try {
            //清除端口配置
            String command = "f1 85 00 02 0b 00";
            iotSerialService.sendCommand(getDeptId(), command, "清除端口配置");
            sleep(1000);
            //设置公共点
            String addressBitmap = redisTemplate.opsForValue().get(DeviceConstants.GGD);
            if (StringUtils.isNotEmpty(addressBitmap)) {
                command = "f1 83 00 03 07 01" + addressBitmap;
                iotSerialService.sendCommand(getDeptId(), command, "设置公共点");
            }
            sleep(1000);
            //获取所有设备信息
            LambdaQueryWrapper<DeviceDevice> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(DeviceDevice::getDelFlag, "0");
            List<DeviceDevice> devices = this.list(wrapper);
            if (CollectionUtils.isNotEmpty(devices)) {
                //非导通设备
                List<DeviceDevice> devices1 = devices.stream().filter(deviceDevice -> "1".equals(deviceDevice.getIsDt())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(devices1)) {
                    devices1.forEach(device -> {
                        if (null != device && StringUtils.isNotEmpty(device.getAddressBitmap())) {
                            //设置设备测量点
                            String command1 = "f1 83 00 04 " + device.getDxbh() + " 02 " + device.getAddressBitmap().replaceAll(",", " ");
                            iotSerialService.sendCommand(device.getDeptId(), command1, "设置" + device.getDeviceName() + "测量点位");
                            sleep(1000);
                        }
                    });
                }
                //导通
                //非导通设备
                List<DeviceDevice> devices0 = devices.stream().filter(deviceDevice -> "0".equals(deviceDevice.getIsDt())).collect(Collectors.toList());
                if (CollectionUtils.isNotEmpty(devices0)) {
                    devices0.forEach(device -> {
                        if (null != device && StringUtils.isNotEmpty(device.getMasterCode()) && StringUtils.isNotEmpty(device.getSlaveCode())) {
                            String bitCode = device.getMasterCode() + "," + device.getSlaveCode();
                            //设置主从测试点
                            String command1 = "f1 83 00 08 " + device.getDxbh() + "0" + bitCode.split(",").length + bitCode.replaceAll(",", " ");
                            iotSerialService.sendCommand(device.getDeptId(), command1, "设置" + device.getDeviceName() + "主从测试点位");
                            sleep(1000);
                        }
                    });
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("重置硬件配置失败！");
        }
        return true;
    }

}
